package com.riekoff.particlecubeworld.editor.visual;

import java.util.ArrayList;
import java.util.List;

import com.riekoff.particlecubeworld.player.ATileWorldBox;

import cc.creativecomputing.CCApp;
import cc.creativecomputing.graphics.CCCamera;
import cc.creativecomputing.graphics.CCDrawMode;
import cc.creativecomputing.graphics.CCGraphics;
import cc.creativecomputing.graphics.CCVBOMesh;
import cc.creativecomputing.graphics.CCViewport;
import cc.creativecomputing.math.CCMath;
import cc.creativecomputing.math.CCVecMath;
import cc.creativecomputing.math.CCVector3f;
import cc.creativecomputing.math.CCVector3i;
import cc.creativecomputing.math.CCVector4f;
import cc.creativecomputing.math.util.CCArcball;
import de.negativrekord.blockworld.MultiPathGenerator;
import de.negativrekord.blockworld.MultiPathGenerator.PathStyle;
import de.negativrekord.blockworld.MultiPathGenerator.StartPositions;

public class ABoxVisualGrowing implements AVisual{

	private CCCamera cam0;
	private CCCamera[] splitCams = new CCCamera[3];	
	private CCVBOMesh _myMesh;
	private final int nDetailLevels = 3;
	private ArrayList<ATileWorldBox>[] _myBoxes = new ArrayList[nDetailLevels];
	private MultiPathGenerator _myPathGenerator = new MultiPathGenerator (10, StartPositions.GRID, 1,0,0,0);
	private int cam = 0;
	
	private int NPATTERN = 10;
	private int NZONES = 10;
	private int NCOLORS = 10;
	
	private CCVector3f[] centersPattern = new CCVector3f[NPATTERN];
	private CCVector3f[] centersZone = new CCVector3f[NZONES];
	private CCVector3f[] centersColor = new CCVector3f[NCOLORS];
	
	int N = 21;
	private int[][][] space = new int[N][N][N];
	
	public CCVector3f[]  centersPattern() {
		return centersPattern;
	}
	
	public CCVector3f[]  centersZone() {
		return centersZone;
	}
	
	public CCVector3f[]  centersColor() {
		return centersColor;
	}
	
	int minScale = 50;
	private void addBoxX (int x, int y, int z, int scale) {
		_myBoxes[0].add(new ATileWorldBox (new CCVector3f(scale,scale,scale), new CCVector3f(x*minScale,y*minScale,z*minScale)));
		for (int i=0; i<scale/minScale; i++) {
			for (int j=0; j<scale/minScale; j++) {
				for (int k=0; k<scale/minScale; k++) {
					if (x+N/2+i>20 || y+N/2+j>20 | z+N/2+k>20)continue;
					space[x+N/2+i][y+N/2+j][z+N/2+k] = 1;
				}
			}
		}
	}
	
	
	int cnt = 0;
	
	public ABoxVisualGrowing(CCApp theApp) {
		for (int i=0; i<nDetailLevels; i++) {
			_myBoxes[i] = new ArrayList<>();
		}
		
		for (int i=0; i<10; i++) {
			centersPattern[i] = new CCVector3f(1f,0f,1f);
			centersZone[i] = new CCVector3f(1f,0f,1f);
			centersColor[i] = new CCVector3f(1f,0f,1f);
		}
		_myMesh = new CCVBOMesh(CCDrawMode.QUADS,40*40*40*24);
		// create geometry
		
		int size0 = 1000;
//		_myBoxes[0].add(new CCBox (new CCVector3f(size0, size0, size0), new CCVector3f(0,0,0)));
		
//		addBoxDetail (1, size0, 200, 0, 1200);
//		addBoxDetail (2, size0, 50, 0, 50);
		
		int w = 10;
		int s = 1;
		for (int x=-N/2; x<=N/2; x+=s) {
			for (int y=-N/2; y<=N/2; y+=s) {
				for (int z=-N/2; z<=N/2; z+=s) {
					
					// method A
//					float dist = new CCVector3f(x,y,z).distance(new CCVector3f(0,0,0));
//					if (dist==0) dist=1;
//					if (CCMath.random()<1f/(dist*dist)) {	
//						addBoxX(x,y,z,100);
//					}
					
//					// method B
//					if ((x==((N/2)-s) || x==-N/2) && CCMath.random()<0.2f) {
//						addBoxX(x,y,z,minScale*s);
//					}
//					if ((y==((N/2)-s) || y==-N/2) && CCMath.random()<0.2f) {
//						addBoxX(x,y,z,minScale*s);
//					}
//					if ((z==((N/2)-s) || z==-N/2) && CCMath.random()<0.2f) {
//						addBoxX(x,y,z,minScale*s);
//					}
					
				}
			}
		}
		
		
		/*
		int ss = 700;
		_myBoxes[0].add(new CCBox(new CCVector3f(ss,ss,ss), new CCVector3f(-ss/2,-ss/2,-ss/2)));
		for (int x=1; x<N-1; x++) {
			for (int y=1; y<N-1; y++) {
				for (int z=1; z<N-1; z++) {
					space[x][y][z] = 1;
				}
			}
		}
		*/
		
		for (int i=0; i<nDetailLevels; i++) {
			for (ATileWorldBox b: _myBoxes[i]) {
				b.addToMesh(_myMesh);
			}
		}
		
		// cam paths
//		_myPathGenerator.addPath(PathStyle.FREE, 100, 0, 1, getRandomBox(0).edge().add(new CCVector3f(-250,550,0)));
		_myPathGenerator.addPathVolumetric(0, 5f, space, 1, N, w);
		_myPathGenerator.addPath(PathStyle.PLANE, 1000, 1, 2f, new CCVector3f(1000,0,0));
		_myPathGenerator.addPath(PathStyle.FREE, 400, 2, 0.1f);
		_myPathGenerator.addPath(PathStyle.CUBE, 800, 3, 1f);
				
		// class center paths
		_myPathGenerator.addPath(PathStyle.FREE, 100, 4, 1);
		_myPathGenerator.addPath(PathStyle.FREE, 100, 5, 1);
		_myPathGenerator.addPath(PathStyle.FREE, 100, 6, 1);
		_myPathGenerator.addPath(PathStyle.FREE, 100, 7, 1);
		_myPathGenerator.addPath(PathStyle.FREE, 100, 8, 1);
		_myPathGenerator.addPath(PathStyle.FREE, 100, 9, 1);
		_myPathGenerator.addPath(PathStyle.FREE, 100, 10,1);
		_myPathGenerator.addPath(PathStyle.FREE, 100, 11, 1);
		_myPathGenerator.addPath(PathStyle.FREE, 100, 12, 1);
		_myPathGenerator.addPath(PathStyle.FREE, 100, 13, 1);
				
		cam0 = new CCCamera(theApp.g);
		cam0.viewport(new CCViewport (0,0,theApp.width,theApp.height));
		cam0.near(1f);
		
		splitCams[0] = new CCCamera(theApp.g);
		splitCams[0].viewport(new CCViewport (0,theApp.height/3,theApp.width/3,theApp.height/3));
		splitCams[1] = new CCCamera(theApp.g);
		splitCams[1].viewport(new CCViewport (theApp.width/3,theApp.height/3,theApp.width/3,theApp.height/3));
		splitCams[1].fov(70);
		splitCams[2] = new CCCamera(theApp.g);
		splitCams[2].viewport(new CCViewport (theApp.width*2/3,theApp.height/3,theApp.width/3,theApp.height/3));	
	}
	
	ATileWorldBox getRandomBox (int theLevel) {
		int ind = (int)CCMath.random(0,_myBoxes[theLevel].size());
		return _myBoxes[theLevel].get(ind);
	}
	
	public CCVector3f center(int n) {
		return _myPathGenerator.spline(n);
	}
	
	CCVector3f[] _myCenters = new CCVector3f[10];
	public CCVector3f[] centers() {
		for (int i=0; i<10; i++) {
			_myCenters[i] = _myPathGenerator.spline(i);
		}
		return _myCenters;
	}
	void addBoxDetail(int theLevel, int size0, int size1, int minH, int maxH) {

		ArrayList<ATileWorldBox> boxes = _myBoxes[theLevel];
		for (int i=0; i<size0/size1; i++) {
			for (int j=0; j<size0/size1; j++) {
				boxes.add(new ATileWorldBox (new CCVector3f(CCMath.random(minH,maxH), size1, size1), new CCVector3f(size0/2,i*size1-size0/2,j*size1-size0/2)));
				boxes.add(new ATileWorldBox (new CCVector3f(CCMath.random(minH,maxH), size1, size1), new CCVector3f(-size0/2,i*size1-size0/2,j*size1-size0/2)));
			}	
		}
		
		for (int i=0; i<size0/size1; i++) {
			for (int j=0; j<size0/size1; j++) {
				boxes.add(new ATileWorldBox (new CCVector3f(size1, CCMath.random(minH,maxH), size1), new CCVector3f(-size0/2+i*size1,-size0/2, -size0/2+j*size1)));
				boxes.add(new ATileWorldBox (new CCVector3f(size1, CCMath.random(minH,maxH), size1), new CCVector3f(-size0/2+i*size1, size0/2, -size0/2+j*size1)));
			}	
		}
		
		for (int i=0; i<size0/size1; i++) {
			for (int j=0; j<size0/size1; j++) {
				boxes.add(new ATileWorldBox (new CCVector3f(size1, size1, CCMath.random(minH,maxH)), new CCVector3f(-size0/2+i*size1,-size0/2+j*size1,-size0/2)));
				boxes.add(new ATileWorldBox (new CCVector3f(size1, size1, CCMath.random(minH,maxH)), new CCVector3f(-size0/2+i*size1,-size0/2+j*size1,size0/2)));
			}	
		}
		
		for (int i=0; i<100; i++) {
			int size = (int)CCMath.random(10,40);
			boxes.add(new ATileWorldBox (new CCVector3f(size,size,size), new CCVector3f(CCMath.random(-200,200),CCMath.random(-200,200),CCMath.random(-200,200))));
		}
	}
	
	public void cam (int theCam) {
		cam = theCam;
	}
	
	public CCCamera getCamera (int theCam) {
		if (theCam==0) return cam0;
		else return splitCams[theCam+1];
	}
	boolean checkSpace (CCVector3f pos) {
		return (space[(int)pos.x+N/2][(int)pos.y+N/2][(int)pos.z+N/2]==1);
	}
	
	CCVector3f randomStart = new CCVector3f((int)CCMath.random(-N/2,N/2), (int)CCMath.random(-N/2,N/2), (int)CCMath.random(-N/2,N/2));
	int frameCount = 0;
	
	public void update (float theDeltaTime) {
		_myPathGenerator.update(theDeltaTime);
		frameCount = (frameCount+1)%40;
		
		for (int i=0; i<10; i++) {
			centersColor[i] = _myPathGenerator.spline(i+4);
		}
		_myPathGenerator.setCamera(cam0, 0);
	}
	
	public CCVector3f target (int index) {
		return _myPathGenerator.spline(index);
	}
	
	
	float cnt2 = 0f;
	@Override
	public void draw(CCGraphics g) {
		/*
		for (int j=0; j<nDetailLevels; j++) {
			for (CCBox box: _myBoxes[j]) {
				
			}
		}
		*/
		cnt2 = 4000;
		int frac = 300;
		int x = (int)CCMath.random(0,cnt2);
		int y = 0; //(int)CCMath.random(-cnt2,cnt2);
		int z = (int)CCMath.random(0,cnt2);
		
		x = ((int)(x/frac))*frac-2000;
		z = ((int)(z/frac))*frac-2000;
		
		if (CCMath.random()<0.1f) {
			cnt2 += 0.5f;
			_myBoxes[0].add(new ATileWorldBox (new CCVector3f (10,CCMath.random(50,400),CCMath.random(50,400)), 
									   new CCVector3f (x,y,z)));
		}
		else if (CCMath.random()<0.02f) {
//			cnt2 += 0.5f;
//			_myBoxes[0].add(new CCBox (new CCVector3f (CCMath.random(100,200),10, CCMath.random(100,200)), 
//					   new CCVector3f (x*30,y*30,z*30)));	
		}
		else if (CCMath.random()<0.4f){
			cnt2 += 0.5f;
			_myBoxes[0].add(new ATileWorldBox (new CCVector3f (CCMath.random(50,400),CCMath.random(50,200),10), 
					   new CCVector3f (x,y,z)));
		}
		
		if (cam==0) {
			cam0.draw(g);
			
			for (int i=0; i<3; i++) {
				for (ATileWorldBox b: _myBoxes[i]) {
					b.draw(g);
				}
			}
//			_myMesh.draw(g);
		}
		else {
			int i = 1;
			splitCams[0].target(new CCVector3f(1000,0,100));
			splitCams[1].target(_myPathGenerator.splineDir(2));
			splitCams[2].target(_myPathGenerator.splineDir(3));
			for (CCCamera c: splitCams) {
				c.position(_myPathGenerator.spline(i));
				i+=1;
				c.draw(g);
				_myMesh.draw(g);
			}
		}
	}
}